/*
*	Copyright (C) 2014  Julio Montes, Mario Carrillo
*	
*	Julio Montes e-mail: imc.coder@gmail.com 
*
*	Mario Carrillo e-mail: mario_90ago@live.com.mx
*
*	BSD 3-Clause License
*/

#include "alliance/include/project.h"

#include "alliance/include/processmgr.h"

#include <wx/tokenzr.h>

#include <algorithm>

namespace alliance
{
    bool sortFunction( const projectFile &e1, const projectFile &e2 )
    {
        if( e1.virtualDirectory == e2.virtualDirectory )
        {
            return e1.filename.Cmp( e2.filename ) < 0;
        }

        if( e1.virtualDirectory.Cmp( e2.virtualDirectory ) < 0 )
        {
            if( e2.virtualDirectory.StartsWith( e1.virtualDirectory ) )
            {
                return false;
            }

            return true;
        }

        if( e1.virtualDirectory.StartsWith( e2.virtualDirectory ) )
        {
            return true;
        }

        return false;
    }

    void Project::CallBackCompile( bool wasCanceled, size_t indexTool, void *caller )
    {
        if( caller != NULL )
        {
            Project *project = static_cast<Project *>( caller );
            project->m_isBusy = false;
        }
    }

    Project::Project()
        : m_isModified( false )
        , m_isBusy( false )
    {

    }

    Project::~Project()
    {

    }

    bool Project::Save()
    {
        m_isModified = false;
        sdk::FileConfig projectFile;
        if( !projectFile.LoadFile( m_filename ) )
        {
            //TODO: Show error, cannot save the project
            return false;
        }

        projectFile.DeleteAllElements( _T( "/alliance" ) );

        std::sort( m_vectorFiles.begin(), m_vectorFiles.end(), sortFunction );

        for( size_t i=0; i<m_vectorFiles.size(); ++i )
        {
            projectFile.WriteNewString( _T( "/alliance/file" ), m_vectorFiles[i].virtualDirectory, _T( "virtual_dir" ) );
            projectFile.WriteString( _T( "/alliance/file" ), m_vectorFiles[i].filename, _T( "name" ), i+1 );
        }

        for( size_t i=0; i<m_vectorTools.size(); ++i )
        {
            m_vectorTools[i].Save( &projectFile );
        }

        return projectFile.Save();
    }

    void Project::Compile()
    {
        m_isBusy = true;
        ProcessManager::Get()->CompileProject( this, CallBackCompile, this );
    }

    bool Project::ReloadFile( const wxString &filename )
    {
        m_vectorTools.clear();
        m_vectorFiles.clear();

        return LoadFile( filename );
    }

    bool Project::LoadFile( const wxString &filename )
    {
        m_isModified = false;
        m_filename = filename;
        m_directory = filename.BeforeLast( _T( '/' ) ) + _T( "/" );

        m_projectName = filename.AfterLast( _T( '/' ) ).BeforeLast( _T( '.' ) );
        if( m_projectName.IsEmpty() )
        {
            m_projectName = filename.AfterLast( _T( '/' ) );
        }

        sdk::FileConfig fileConfig;
        if( !fileConfig.LoadFile( filename ) )
        {
            return false;
        }

        sdk::vectorElementsString vectorElements;
        fileConfig.ReadElements( _T( "/alliance/file" ), &vectorElements );
        for( size_t i=0; i<vectorElements.size(); ++i )
        {
            AddFile( vectorElements[i].vectorAttributes );
        }

        vectorElements.clear();
        fileConfig.ReadElements( _T( "/alliance/tools/tool" ), &vectorElements );
        for( size_t i=0; i<vectorElements.size(); ++i )
        {
            sdk::vectorElementsString vectorChildren;
            fileConfig.ReadChildren( _T( "/alliance/tools/tool" ), &vectorChildren, i+1 );

            wxString toolCommand;
            wxString toolCommandFormat;
            for( size_t j=0; j<vectorElements[i].vectorAttributes.size(); ++j )
            {
                if( 0 == vectorElements[i].vectorAttributes[j].name.CmpNoCase( _T( "value" ) ) )
                {
                    toolCommand = vectorElements[i].vectorAttributes[j].value;
                }
                else if( 0 == vectorElements[i].vectorAttributes[j].name.CmpNoCase( _T( "format" ) ) )
                {
                    toolCommandFormat = vectorElements[i].vectorAttributes[j].value;
                }
            }

            if( !toolCommand.IsEmpty() && !toolCommandFormat.IsEmpty() )
            {
                Tool tool( toolCommand, toolCommandFormat );
                m_vectorTools.push_back( tool );
                m_vectorTools.back().Load( vectorChildren );
            }
        }

        return true;

    }

    bool Project::RemoveFile( const wxString &filePath )
    {
        for( size_t i=0; i<m_vectorFiles.size(); ++i )
        {
            if( m_vectorFiles[i].filename == filePath )
            {
                m_vectorFiles.erase( m_vectorFiles.begin() + i );
                m_isModified = true;
                return true;
            }
        }
        return false;
    }

    bool Project::RenameFile( const wxString &filePath, const wxString &newFilePath )
    {
        if( wxFileExists( newFilePath ) )
        {
            int result = wxMessageBox( wxT( "The file: " ) + newFilePath +
                    wxT( " already exists, you want replace this?" ),
                    wxT( "Add files" ), wxYES | wxNO | wxCANCEL | wxICON_QUESTION );

            if( result != wxYES )
            {
                return false;
            }

        }

        if( wxRenameFile( filePath, newFilePath ) )
        {
            for( size_t i=0; i<m_vectorFiles.size(); ++i )
            {
                if( m_vectorFiles[i].filename == filePath )
                {
                    RemoveFile( filePath );
                    AddFile( newFilePath, m_vectorFiles[i].virtualDirectory );
                }
            }

            return true;
        }

        return false;
    }

    void Project::AddFile( const sdk::vectorAttributesString &vectorAttributes )
    {
        projectFile l_projectFile;

        for( size_t i=0; i<vectorAttributes.size(); ++i )
        {
            if( 0 == vectorAttributes[i].name.CmpNoCase( _T( "virtual_dir" ) ) )
            {
                l_projectFile.virtualDirectory = vectorAttributes[i].value;
            }
            else if( 0 == vectorAttributes[i].name.CmpNoCase( _T( "name" ) ) )
            {
                l_projectFile.filename = vectorAttributes[i].value;
            }
        }

        //Fixed virtual path
        wxString virtual_dir;
        wxStringTokenizer st( l_projectFile.virtualDirectory, _T( "/\\" ), wxTOKEN_STRTOK );
        while( st.HasMoreTokens() )
        {
            virtual_dir += st.GetNextToken() + _T( "/" );
        }

        l_projectFile.virtualDirectory = virtual_dir;

        m_vectorFiles.push_back( l_projectFile );

    }

    void Project::AddFile( const wxString &filePath, const wxString &virtualDirectory )
    {
        m_isModified = true;
        projectFile l_projectFile;
        l_projectFile.filename = filePath;
        l_projectFile.virtualDirectory = virtualDirectory;

        RemoveFile( filePath );//to avoid duplicates

        m_vectorFiles.push_back( l_projectFile );
    }


    void Project::AddTool( const alliance::Tool &tool )
    {
        m_isModified = true;
        m_vectorTools.push_back( tool );
    }

    void Project::RemoveAllTools()
    {
        m_isModified = true;
        m_vectorTools.clear();
    }

    const std::vector<Tool> &Project::GetTools() const
    {
        return m_vectorTools;
    }

    const std::vector<projectFile> &Project::GetFiles() const
    {
        return m_vectorFiles;
    }

    const wxString &Project::GetFilename() const
    {
        return m_filename;
    }

    const wxString &Project::GetDirectory() const
    {
        return m_directory;
    }

    const wxString &Project::GetName() const
    {
        return m_projectName;
    }

    bool Project::IsModified() const
    {
        return m_isModified;
    }

    bool Project::IsBusy() const
    {
        return m_isBusy;
    }
}
